package com.grt.condify.reflect;


import com.grt.condify.common.Reports;
import com.grt.condify.common.converter.IConverter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.grt.condify.utils.PreConditionCheck.checkNotNull;


/**
 * 将class信息封装到Map的缓存类,该类实现主要类的保存工作,为具体的后续具体实现提供基类实现
 * <p>
 * 该类实现提供了两级缓存,我们能够把类信息及对应二级缓存信息保存到一级缓存当中,然后二级缓存保存具体的实体
 * 例如:我们需要积累一个类的Setter方法,我们可以将Class或ClassName与字段与其Setter的映射保存到一级缓存当中,即:
 * (className -> ((fieldName -> setter) ... ))
 * <p>
 * Created by cy on 16/5/30.
 */
public abstract class Class2MapInNonStaticCache<K, T, V> {

    /**
     * 缓存实体,该实体可以用来作为缓存,如果子类不使用该缓存,可以自行定义缓存““
     */
    protected Map<K, Map<T, V>> firstLevelCaches = new HashMap<>();


    /**
     * 二级缓存,主要基类将class信息保存到二级的Map中
     */
    protected final Map<T, V> secondLevelCache = new HashMap<>();

    protected Map<K, List<V>> lazyValueList = new HashMap<>();    //延迟加载的所有值的List,主要在存在直接获得V的列表时能够减少遍历时间而设置,该类会在第一次调用时被加载
    private Map<K, Boolean> hasValueListBeLoaded = new HashMap<>();  //value list 是否已经被加载,该值在第一次被加载时被修改

    public abstract boolean isKeyEmpty(K key);

    public abstract boolean isKeyOfMapEmpty(T keyOfMap);

    public abstract boolean isValueIsEmpty(V value);

    /**
     * 缓存指定内容，该内容以主键形式提供
     * <p>
     * 这里缓存了Class的完整名称和其字段方法的映射关系.缓存按照{@code cache(key,value,true) }方式进行存储
     *
     * @param key   被缓存内容的键值
     * @param value 被缓存内容的值
     * @throws RuntimeException - 如果出现缓存失败，抛出该异常
     */
    public void cache(K key, Map<T, V> value) throws RuntimeException {
        cache(key, value, true);
    }

    /**
     * 缓存指定内容，该内容以主键形式提供
     * <p>
     * 这里缓存了Class的完整名称和其字段方法的映射关系.如果isReplace是true,将{@code value}完全替换
     *
     * @param key       被缓存内容的键值
     * @param value     被缓存内容的值
     * @param isReplace 如果Key已经存在,是否替换
     * @throws RuntimeException
     */
    public void cache(K key, Map<T, V> value, boolean isReplace) throws RuntimeException {
        if (isKeyEmpty(key) || value == null || value.size() == 0) {
            return;
        }
        try {
            final Map<T, V> curMap = isContain(key) ? firstLevelCaches.get(checkNotNull(key)) : new HashMap<T, V>();
            if (isReplace || !curMap.containsKey(key))    //如果需要缓存或当前缓存不存在该key值,保存进缓存中
            {
                curMap.putAll(value);
            }
            firstLevelCaches.put(key, curMap);    //更新缓存
            hasValueListBeLoaded.put(key, false);    //值列表需要更新
        } catch (Exception ex) {
            Reports reports = Reports.createNewReports(Class2MehtodInNonStaticCache.class.getName());
            reports.error(ex, 10);
            IConverter converter = new Reports.ObjectToStringConverter();
            throw new RuntimeException(String.format("error when save [%s -> %s] into caches in statement of [%s], " +
                    "the error information is [%s]", "isReplace is " + String.valueOf(isReplace), converter.convert(key), converter.convert(value), reports.reportFailInfoAsJson()));
        }
    }

    /**
     * 按照指定的key值进行缓存的查询工作
     *
     * @param key 指定的值
     * @return key对应的缓存结果
     */
    public List<Map<T, V>> search(K key) {
        if (isKeyEmpty(key)) {
            return null;
        }
        final Map<T, V> resultCache =
                firstLevelCaches.size() > 0 ?
                        firstLevelCaches.containsKey(key) ? firstLevelCaches.get(key)
                                : null : null;
        List<Map<T, V>> wrappedResult = new ArrayList<>();
        wrappedResult.add(resultCache);
        return wrappedResult;
    }

    /**
     * 删除指定key对应的缓存,如果没有找到k对应的缓存,则不进行任何操作
     *
     * @param key
     */
    public void drop(K key) {
        if (!isKeyEmpty(key)) {
            firstLevelCaches.remove(key);

        }
    }

    /**
     * 删除所有的缓存内容
     */
    public void drop() {
        if (firstLevelCaches.size() > 0) {
            firstLevelCaches.clear();
        }
    }

    /**
     * 判断是否存在指定的
     *
     * @param key
     * @return
     */
    public boolean isContain(K key) {

        return isKeyEmpty(key) ? false : firstLevelCaches.containsKey(key);
    }

    /**
     * 得到指定key所有的Value值,即通过Key获得所有的末节点的值列表,如果列表已经被加载过,则会直接返回该列表,否则需要重新解析一次
     * 任何新数据的插入,都会需要重新解析和加载该类
     *
     * @param key
     * @return
     */
    public List<V> getValueList(K key) throws IllegalArgumentException {
        if (isKeyEmpty(key)) {
            throw new IllegalArgumentException("the specified key is empty !");
        }
        if (hasValueListBeLoaded.containsKey(key) && hasValueListBeLoaded.get(key) == true)    //如果缓存中已经加载
        {
            return lazyValueList.get(key);
        } else {  //否则,重新解析并重新缓存
            final Map<T, V> keyFieldMethodMap = firstLevelCaches.containsKey(key) ? firstLevelCaches.get(key) : null;
            if (keyFieldMethodMap != null && keyFieldMethodMap.size() > 0) {
                List<V> valueList = new ArrayList<>();
                for (T keyOfValue : keyFieldMethodMap.keySet()) {
                    valueList.add(keyFieldMethodMap.get(keyOfValue));
                }
                lazyValueList.put(key, valueList);
                hasValueListBeLoaded.put(key, true);
            }
            return lazyValueList.get(key);
        }
    }
}
